package com.reebake.ideal.security.service.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.reebake.ideal.constants.CommonConstants;
import com.reebake.ideal.holder.UserContextHolder;
import com.reebake.ideal.permission.client.MenuClient;
import com.reebake.ideal.permission.entity.MenuDTO;
import com.reebake.ideal.security.service.entity.AuthMenuMetaVO;
import com.reebake.ideal.security.service.entity.AuthMenuVO;
import com.reebake.ideal.security.service.entity.AuthUserInfo;
import com.reebake.ideal.security.service.entity.MenuTreeNode;
import com.reebake.ideal.user.client.UserInfoClient;
import com.reebake.ideal.user.entity.UserInfoDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@RestController
@RequiredArgsConstructor
public class UserSecurityController {
    private final UserInfoClient userInfoClient;
    private final MenuClient menuClient;
    public static final String ROOT_ID = "0";

    @GetMapping("/user/info")
    public AuthUserInfo userInfo(Principal principal) {
        String userId = UserContextHolder.getCurrentUserId();
        AuthUserInfo authUserInfo = new AuthUserInfo();
        if(StrUtil.isBlank(userId)) {
            return authUserInfo;
        }
        UserInfoDTO userInfo = userInfoClient.queryByUserId(userId);
        authUserInfo.setAvatar(userInfo.getAvatar());
        authUserInfo.setRealName(userInfo.getNickname());
        authUserInfo.setDesc(userInfo.getDescription());
        authUserInfo.setUsername(principal.getName());
        List<String> roles = new ArrayList<>();
        Collection<?> authorities = (Collection<?>) BeanUtil.getFieldValue(principal, CommonConstants.ATTRIBUTE_NAME_AUTHORITIES);
        authorities.forEach(it -> {
            roles.add(it.toString());
        });
        authUserInfo.setRoles(ArrayUtil.toArray(roles, String.class));

        return authUserInfo;
    }

    @GetMapping("/auth/codes")
    public List<String> accessCodes() {
        String userId = UserContextHolder.getCurrentUserId();
        return menuClient.queryAccessCodeByUserId(userId);
    }

    @GetMapping("/menu/all")
    public List<AuthMenuVO> menus() {
        String userId = UserContextHolder.getCurrentUserId();
        List<MenuDTO> menus = menuClient.queryMenuByUserId(userId);
        List<MenuTreeNode> menuTreeNodes = tree(menus);
        return convert(menuTreeNodes);
    }

    private List<AuthMenuVO> convert(List<MenuTreeNode> nodes) {
        List<AuthMenuVO> list = new ArrayList<>();
        for(MenuTreeNode node : nodes) {
            AuthMenuVO menu = new AuthMenuVO();
            menu.setComponent(node.getComponent());
            menu.setPath(node.getPath());
            menu.setName(node.getName());
            menu.setRedirect(node.getRedirect());
            AuthMenuMetaVO meta = new AuthMenuMetaVO();
            menu.setMeta(meta);
            meta.setTitle(node.getTitle());
            meta.setIcon(node.getIcon());
            meta.setAffixTab(node.getAffixTab());
            meta.setOrder(node.getOrderNo());
            meta.setHideInMenu(node.getHiddenInMenu());
            meta.setIframeSrc(node.getIframeSrc());
            meta.setLink(node.getLink());
            meta.setKeepAlive(node.getKeepAlive());
            meta.setQuery(node.getQuery());
            meta.setOpenInNewWindow(node.getOpenInNewWindow());
            meta.setNoBasicLayout(node.getNoBasicLayout());
            meta.setIgnoreAccess(node.getIgnoreAccess());

            List<AuthMenuVO> children = convert(node.getChildren());
            menu.setChildren(children);
            list.add(menu);
        }
        return list;
    }

    public List<MenuTreeNode> tree(List<MenuDTO> menus) {
        List<MenuTreeNode> roots = root(menus);
        iterationTree(roots, menus);
        return roots;
    }

    private List<MenuTreeNode> root(List<MenuDTO> menus) {
        List<MenuTreeNode> menuTreeNodes = new ArrayList<>();
        for(MenuDTO menu : menus) {
            if(ROOT_ID.equals(menu.getParentId())) {
                menuTreeNodes.add(BeanUtil.copyProperties(menu, MenuTreeNode.class));
            }
        }
        return menuTreeNodes;
    }

    private void iterationTree(List<MenuTreeNode> menuTreeNodes, List<MenuDTO> menus) {
        if(CollectionUtil.isEmpty(menuTreeNodes)) {
            return;
        }
        for(MenuTreeNode menuTreeNode : menuTreeNodes) {
            for(MenuDTO menu : menus) {
                if(menuTreeNode.getMenuId().equals(menu.getParentId())) {
                    menuTreeNode.getChildren().add(BeanUtil.copyProperties(menu, MenuTreeNode.class));
                }
            }
            iterationTree(menuTreeNode.getChildren(), menus);
        }
    }
}
